<template>
    <view :class="ns.b()" :style="containerStyle">
        <template v-if="controlsPositionArray.length !== 0">
            <view v-for="(item, index) in controlsArray" :key="index" class="item" :style="itemStyle(index)">
                <view
                    class="list-item"
                    @touchstart="onHandleTouchstart($event, index)"
                    @touchmove="onHandleTouchmove"
                    @touchend="onHandleTouchend"
                >
                    <slot :row="item" :last="index === controlsArray.length - 1" />
                </view>
            </view>
        </template>
    </view>
</template>

<script setup lang="ts">
import { useNamespace } from "@/hooks";

const ns = useNamespace("drag");

const emits = defineEmits(["change"]);

const props = defineProps({
    controlsSize: {
        type: Object,
        default: () => ({
            height: 40
        })
    },
    list: {
        type: Array,
        default: () => []
    },
    animationDuration: {
        type: Number,
        default: 0.3
    }
});

const containerStyle = computed(() => {
    return { height: props.controlsSize.height * props.list.length + "rpx" };
});

const controlsArray = ref([]);

const margin = ref({
    margin_x: 0,
    margin_y: 0
});

const recordInitControlsPoisitonList = ref([]);

const controlsPositionArray = ref<{ top: number; left: number }[]>([]);

const recordPosition = ref({
    x: 0,
    y: 0
});

// 记录当前操作的控件数据
const recordControlsPositionItem = ref({});

// 当前操作的控件的下标
const currentControlsIndex = ref(-1);

const itemStyle = computed(() => {
    return (index: number) => {
        return {
            transition: currentControlsIndex.value === index ? "initial" : `${props.animationDuration}s`,
            "z-index": currentControlsIndex.value === index ? 1 : 0,
            height: props.controlsSize.height + "rpx",
            top: controlsPositionArray.value[index].top + "rpx",
            left: controlsPositionArray.value[index].left + "rpx"
        };
    };
});

/** 初始化各个控件的位置 */
const initControlsPosition = () => {
    // 用于返回出去的新数组
    let tempArray = [];

    // 设置控件位置
    for (let i = 0, j = 0; i < props.list.length; i++, j++) {
        tempArray[i] = {
            left: margin.value.margin_x,
            top: j * (props.controlsSize.height + margin.value.margin_y) + margin.value.margin_y
        };
    }

    // 记录数据 - 进行深拷贝
    recordInitControlsPoisitonList.value = [...tempArray];
    // 返回数据
    return tempArray;
};

/** 处理手指触摸后移动 */
const onHandleTouchmove = (event) => {
    const { pageX, pageY } = event.touches[0];

    // 获取移动的差
    controlsPositionArray.value[currentControlsIndex.value] = {
        left: controlsPositionArray.value[currentControlsIndex.value].left + (pageX - recordPosition.value.x),
        top: controlsPositionArray.value[currentControlsIndex.value].top + (pageY - recordPosition.value.y)
    };
    // 记录位置
    recordPosition.value = {
        x: pageX,
        y: pageY
    };
    // 判断当前移动的位置是否需要进行排序
    // 向下移动
    if (
        currentControlsIndex.value !== controlsPositionArray.value.length - 1 &&
        controlsPositionArray.value[currentControlsIndex.value].top >
            controlsPositionArray.value[currentControlsIndex.value + 1].top
    ) {
        // 交换位置
        _handleChangeControlsPosition(0, currentControlsIndex.value + 1);
    }
    // 向上移动
    else if (
        currentControlsIndex.value !== 0 &&
        controlsPositionArray.value[currentControlsIndex.value].top <
            controlsPositionArray.value[currentControlsIndex.value - 1].top
    ) {
        // 交换位置
        _handleChangeControlsPosition(0, currentControlsIndex.value - 1);
    }
};

/** 处理手指触摸开始事件 */
const onHandleTouchstart = (event, index) => {
    const { pageX, pageY } = event.touches[0];

    currentControlsIndex.value = index;
    recordPosition.value = {
        x: pageX,
        y: pageY
    };

    recordControlsPositionItem.value = controlsPositionArray.value[index];
    uni.vibrateShort();
};

/** 处理手指松开事件 */
const onHandleTouchend = () => {
    // 将操控的控件归位
    controlsPositionArray.value[currentControlsIndex.value] =
        recordInitControlsPoisitonList.value[currentControlsIndex.value];
    currentControlsIndex.value = -1;

    emits("change", controlsArray.value);
};

/**
 * 处理交换控件位置的方法 -
 * @param {number} index    需要与第几个下标交换位置
 * */
const _handleChangeControlsPosition = (type, index) => {
    // 记录当前操控的控件数据
    let tempControls = controlsArray.value[currentControlsIndex.value];

    // 设置原来位置的数据
    controlsArray.value[currentControlsIndex.value] = controlsArray.value[index];
    // 将临时存放的数据设置好
    controlsArray.value[index] = tempControls;

    // 调整控件位置数据
    controlsPositionArray.value[index] = controlsPositionArray.value[currentControlsIndex.value];
    controlsPositionArray.value[currentControlsIndex.value] = recordControlsPositionItem.value;

    // 改变当前选中的位置
    currentControlsIndex.value = index;

    // 记录新位置的数据
    recordControlsPositionItem.value = recordInitControlsPoisitonList.value[currentControlsIndex.value];

    uni.vibrateShort();
};

onMounted(() => {
    // 获取控件列表
    controlsArray.value = props.list;

    // 初始化控件的位置
    controlsPositionArray.value = initControlsPosition();
});
</script>

<style scoped lang="scss">
@import "./index";
</style>
